package lokiunifi

import (
	"fmt"
	"strings"
	"time"

	"github.com/unpoller/unifi/v5"
	"github.com/unpoller/unpoller/pkg/poller"
)

// LogStream contains a stream of logs (like a log file).
// This app uses one stream per log entry because each log may have different labels.
type LogStream struct {
	Labels  map[string]string `json:"stream"` // "the file name"
	Entries [][]string        `json:"values"` // "the log lines"
}

// Logs is the main logs-holding structure. This is the Loki-output format.
type Logs struct {
	Streams []LogStream `json:"streams"` // "multiple files"
}

// Report is the temporary data generated by processing events.
type Report struct {
	Start  time.Time
	Oldest time.Time
	poller.Logger
	Counts map[string]int
}

// NewReport makes a new report.
func (l *Loki) NewReport(start time.Time) *Report {
	return &Report{
		Start:  start,
		Oldest: l.last,
		Logger: l,
		Counts: make(map[string]int),
	}
}

// ProcessEventLogs loops the event Logs, matches the interface type, calls the
// appropriate method for the data, and compiles the Logs into a Loki format.
// This runs once per interval, if there was no collection error.
func (r *Report) ProcessEventLogs(events *poller.Events) *Logs {
	logs := &Logs{}

	for _, e := range events.Logs {
		switch event := e.(type) {
		case *unifi.IDS:
			r.IDs(event, logs)
		case *unifi.Event:
			r.Event(event, logs)
		case *unifi.Alarm:
			r.Alarm(event, logs)
		case *unifi.Anomaly:
			r.Anomaly(event, logs)
		default: // unlikely.
			r.LogErrorf("unknown event type: %T", e)
		}
	}

	return logs
}

func (r *Report) String() string {
	return fmt.Sprintf("%s: %d, %s: %d, %s: %d, %s: %d, Dur: %v",
		typeEvent, r.Counts[typeEvent], typeIDs, r.Counts[typeIDs],
		typeAlarm, r.Counts[typeAlarm], typeAnomaly, r.Counts[typeAnomaly],
		time.Since(r.Start).Round(time.Millisecond))
}

// CleanLabels removes any tag that is empty.
func CleanLabels(labels map[string]string) map[string]string {
	for i := range labels {
		if strings.TrimSpace(labels[i]) == "" {
			delete(labels, i)
		}
	}

	return labels
}
